/*
 * Copyright (c) 2021 Talkweb Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <unistd.h>
#include "stdio.h"
#include "ohos_init.h"
#include "cmsis_os2.h"

#include "sensor.h"
#include "iot_errno.h"
#include "iot_gpio.h"
#include "iot_gpio_ex.h"

/**
 * @brief 写数据
 * @param buffer  数据区
 * @param length  数据长度
 * @return IOT_SUCCESS:成功  IOT_FAILURE：失败
 */
static uint32_t Aht20I2cWrite(uint8_t *buffer, uint32_t length)
{
    uint32_t status;
    status = IoTI2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, buffer, length);
    if (status != IOT_SUCCESS)
    {
        printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
        return status;
    }
    return IOT_SUCCESS;
}

/**
 * @brief 读数据
 * @param buffer  读取到数据区
 * @param length  数据长度
 * @return IOT_SUCCESS:成功  IOT_FAILURE：失败
 */
static uint32_t Aht20I2cRead(uint8_t *buffer, uint32_t length)
{
    uint32_t receive_data;

    receive_data = IoTI2cRead(AHT20_I2C_IDX, AHT20_WRITE_ADDR, buffer, length);
    if (receive_data != IOT_SUCCESS)
    {
        printf("===== hi_i2c_read failed, 0x%x! =====\r\n", receive_data);
        return receive_data;
    }
    return IOT_SUCCESS;
}

// 发送软复位命令
static uint32_t Aht20ResetCommand(void)
{
    uint8_t resetCmd[] = {AHT20_CMD_RESET};
    return Aht20I2cWrite(resetCmd, sizeof(resetCmd));
}

// 发送初始化校准命令
static uint32_t Aht20CalibrateCommand(void)
{
    uint8_t clibrateCmd[] = {AHT20_CMD_CALIBRATION, AHT20_CMD_CALIBRATION_ARG0, AHT20_CMD_CALIBRATION_ARG1};
    return Aht20I2cWrite(clibrateCmd, sizeof(clibrateCmd));
}

/***
 * @brief 上电后判断状态
 * @brief 如果设备忙或未校准 则重启设备并校准
 * @return IOT_SUCCESS:成功  其它值：失败
 */
static unsigned int Aht20Calibrate(void)
{
    uint8_t RevBuffer[AHT20_RECEIVE_MAX];
    uint8_t statusCmd[] = {AHT20_CMD_STATE}; //状态字指令
    uint32_t retval = 0;

    retval = Aht20I2cWrite(statusCmd, sizeof(statusCmd)); //发送状态字指令
    if (retval != IOT_SUCCESS)
    {
        return retval;
    }

    retval = Aht20I2cRead(RevBuffer, sizeof(RevBuffer)); //接收状态字
    if (retval != IOT_SUCCESS)
    {
        return retval;
    }

    // 设备忙或未校准
    if ((RevBuffer[0] & 0x80) || !(RevBuffer[0] & 0x08)) 
    {
        // 调用软启动命令，重启设备
        retval = Aht20ResetCommand(); 
        if (retval != IOT_SUCCESS)
        {
            return retval;
        }

        // 重启所需时间
        usleep(20 * 1000);        
        // 校准命令        
        retval = Aht20CalibrateCommand(); 
        // 校准所需时间
        usleep(40 * 1000);                
        
        return retval;
    }
    return IOT_SUCCESS;
}

/**
 * @brief 发送 触发测量 命令，开始测量
 * @return IOT_SUCCESS:成功  IOT_FAILURE：失败
 */
static uint32_t Aht20StartMeasure(void)
{
    uint8_t triggerCmd[] = {AHT20_CMD_TRIGGER, AHT20_CMD_TRIGGER_ARG0, AHT20_CMD_TRIGGER_ARG1};
    return Aht20I2cWrite(triggerCmd, sizeof(triggerCmd));
}

/**
 * @brief 接收测量结果，拼接转换为标准值
 * @param[out]  temp  温度值
 * @param[out]  humi
 * @return   IOT_SUCCESS:成功  IOT_FAILURE：失败
 */
static uint32_t Aht20GetMeasureResult(float *temp, float *humi)
{
    uint32_t retval = 0, i = 0;
    uint8_t buffer[AHT20_RECEIVE_MAX];

    if (temp == NULL || humi == NULL)
    {
        return IOT_FAILURE;
    }

    memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer));
    retval = Aht20I2cRead(buffer, sizeof(buffer)); // recv status command result
    if (retval != IOT_SUCCESS)
    {
        return retval;
    }

    for (i = 0; ((buffer[0] & 0x80) >> 7) && i < AHT20_MAX_RETRY; i++)
    {
        usleep(75 * 1000);
        retval = Aht20I2cRead(buffer, sizeof(buffer)); // recv status command result
        if (retval != IOT_SUCCESS)
        {
            return retval;
        }
    }
    if (i >= AHT20_MAX_RETRY)
    {
        printf("AHT20 device always busy!\r\n");
        return IOT_FAILURE;
    }

    //转换
    uint32_t humiRaw = buffer[1];
    humiRaw = (humiRaw << 8) | buffer[2];
    humiRaw = (humiRaw << 4) | ((buffer[3] & 0xF0) >> 4);
    *humi = humiRaw / (float)(1 << 20) * 100;

    uint32_t tempRaw = buffer[3] & 0x0F;
    tempRaw = (tempRaw << 8) | buffer[4];
    tempRaw = (tempRaw << 8) | buffer[5];
    *temp = tempRaw / (float)(1 << 20) * 200 - 50;

    return IOT_SUCCESS;
}

/**
 * @brief 任务线程执行循环
 * @param   arg  参数
 */
static void *THSensorTask(const char *arg)
{
    (void)arg;
    uint32_t retval = 0;

    float temp = 0.0, humi = 0.0;

    //校准设备
    retval = Aht20Calibrate();
    printf("AHT20_Calibrate: %d\r\n", retval);

    while (1)
    {
        //工作循环
        retval = Aht20StartMeasure();
        if (retval == IOT_SUCCESS)
        {
            retval = Aht20GetMeasureResult(&temp, &humi);
            if (retval == IOT_SUCCESS)
            {
                printf("AHT20 GetMeasureResult: temp = %.2f, humi = %.2f\r\n", temp, humi);
            }
        }

        osDelay(100);
    }
    return NULL;
}

static void THSensorExample(void)
{
    osThreadAttr_t attr;

    // 初始化IIC
    IoTGpioInit(IOT_IO_NAME_GPIO_13);
    IoTGpioInit(IOT_IO_NAME_GPIO_14);

    IoSetPull(IOT_IO_NAME_GPIO_13, IOT_IO_PULL_UP);
    IoSetPull(IOT_IO_NAME_GPIO_14, IOT_IO_PULL_UP);

    IoSetFunc(IOT_IO_NAME_GPIO_13, IOT_IO_FUNC_GPIO_13_I2C0_SDA);	
    IoSetFunc(IOT_IO_NAME_GPIO_14, IOT_IO_FUNC_GPIO_14_I2C0_SCL);	

    // 设置IIC速率 100K
    IoTI2cInit(IOT_I2C_IDX_0, 100 * 1000);

    attr.name = "THSensorTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = THSENSOR_TASK_STACK_SIZE;
    attr.priority = THSENSOR_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)THSensorTask, NULL, &attr) == NULL)
    {
        printf("[THSensorExample] Falied to create THSensorTask!\n");
    }
}

APP_FEATURE_INIT(THSensorExample);
